#include "StdAfx.h"
#include "P2PSession.h"
#include "P2P.h"
#include "P2PProtocolImpl.h"

CHostSession::CHostSession( CP2P* p2p )
{
    m_p2p = p2p;
}

void CHostSession::OnEstablish( HNETHANDLE hHandle, HSESSION hSession )
{
    LoginReq req;

    req.local_ip = m_p2p->get_net_manager()->GetLocalIP(hSession);
    req.local_port = m_p2p->get_net_manager()->GetLocalPort(hSession);
    
    if (!SendPkg(&req))
    {
        DisConnect();
    }
}

void CHostSession::OnTerminate( HSESSION hSession )
{
    if (!m_p2p->get_nat_type())
    {
        m_p2p->get_p2p_session_call_back()->OnLogin(-1, 0);
    }
    set_session(NULL);
    m_p2p->set_p2p_id(0);
    m_p2p->set_nat_type(0);
}

void CHostSession::OnError( HNETHANDLE hHandle, HSESSION hSession, INT32 iModuleError, INT32 iSystemError )
{
    if (iModuleError == NET_CONNECT_FAIL)
    {
        m_p2p->get_p2p_session_call_back()->OnLogin(-1, 0);
        set_session(NULL);
        m_p2p->set_p2p_id(0);
        m_p2p->set_nat_type(0);
    }
}

void CHostSession::OnRecv( HSESSION hSession, const char* pData, const INT32 iLen )
{
    char* ptr = (char*)pData + sizeof(INT32);
    INT32 size = iLen - sizeof(INT32);

    m_p2p->set_current_host_session(this);
    m_p2p->get_p2p_protocol_impl().HandleClientPkg(ptr, size);
    m_p2p->set_current_host_session(NULL);
}

bool CHostSession::SendPkg( void* host )
{
    char* pkg = NULL;
    
    int pkg_len = m_p2p->get_p2p_protocol_impl().BuildPkg(host, pkg);

    if (pkg_len < 0)
    {
        return false;
    }

    if (!m_session)
    {
        return false;
    }

    return m_p2p->get_net_manager()->Send(m_session, pkg, pkg_len);
}

void CHostSession::DisConnect( void )
{
    if (m_session)
    {
        m_p2p->get_net_manager()->DisConnect(m_session);
        m_session = NULL;
    }
}

CP2PSession::CP2PSession(void)
{
}

CP2PSession::~CP2PSession(void)
{
}

void CP2PSession::OnEstablish( HNETHANDLE hHandle, HSESSION hSession )
{
    m_session = hSession;
    m_net_handle = hHandle;

    if (hHandle == hSession)
    {
        P2PHandleReq stReq;
        stReq.my_p2p_id = m_p2p->get_p2p_id();

        if (!SendPkg(&stReq))
        {
            DisConnect();
        }
    }
    set_stat(P2P_STAT_ESTABLISH);
}

void CP2PSession::OnTerminate( HSESSION hSession )
{
    if (get_stat() == P2P_STAT_OK)
    {
        m_p2p->get_p2p_session_call_back()->OnClose(m_p2p_id);
        m_p2p->get_p2p_session_manager().DelP2PSession(m_p2p_id);
    }

    m_session = NULL;
    m_stat = P2P_STAT_INT;

    m_p2p->get_p2p_timer_manager().DelTimer(this);
    m_p2p->get_p2p_session_manager().get_p2p_session_pool().FreeObj(this);
}

void CP2PSession::OnError( HNETHANDLE hHandle, HSESSION hSession, INT32 iModuleError, INT32 iSystemError )
{
    if (iModuleError == NET_CONNECT_FAIL)
    {
        m_session = NULL;
        m_stat = P2P_STAT_INT;
    }
    //m_p2p->get_p2p_session_call_back()->OnError(m_p2p_id, iModuleError);
}

void CP2PSession::OnRecv( HSESSION hSession, const char* pData, const INT32 iLen )
{
    char* ptr = (char*)pData + sizeof(INT32);
    INT32 size = iLen - sizeof(INT32);

    m_p2p->set_current_p2p_session(this);
    if (get_stat() == P2P_STAT_OK)
    {
        m_p2p->get_p2p_session_call_back()->OnData(m_p2p_id, pData, iLen);
    }
    else
    {
        m_p2p->get_p2p_protocol_impl().HandleClientPkg(ptr, size);
    }
    
    m_p2p->set_current_p2p_session(NULL);
}

bool CP2PSession::Start(void)
{
    PeerInfo* peer_info = m_p2p->get_p2p_session_manager().FindPeerInfo(m_p2p_id);
    if (!peer_info)
    {
        return false;
    }

    set_local_ip(m_p2p->get_net_manager()->GetLocalIP(m_p2p->get_host().get_session()));
    set_local_port(m_p2p->get_net_manager()->GetLocalPort(m_p2p->get_host().get_session()));

    set_peer_ip(peer_info->public_ip);
    set_peer_port(peer_info->public_port);

    if (!Connect())
    {
        return false;
    }

    set_stat(P2P_STAT_CONNECTING);

    set_elapse(1000);

    set_count(-1);

    return m_p2p->get_p2p_timer_manager().AddTimer(this);
}

void CP2PSession::OnTimer( void )
{
    if (m_stat != P2P_STAT_INT || m_session != NULL)
    {
        return;
    }

    Connect();
}

bool CP2PSession::Connect( void )
{
    char local_ip[32];
    char peer_ip[32];

    sockaddr_in addr;
    addr.sin_addr.s_addr = m_local_ip;
    strcpy(local_ip, inet_ntoa(addr.sin_addr));

    addr.sin_addr.s_addr = m_peer_ip;
    strcpy(peer_ip, inet_ntoa(addr.sin_addr));

    m_session = m_p2p->get_net_manager()->Connect(peer_ip, ntohs(m_peer_port), 1024, 1024, &(m_p2p->get_pkg_parser()), local_ip, ntohs(m_local_port), true);
    if (m_session)
    {
        m_p2p->get_net_manager()->SetSessionUserData(m_session, this);

        set_stat(P2P_STAT_CONNECTING);

        return true;
    }

    return false;
}

bool CP2PSession::SendPkg( void* host )
{
    char* pkg = NULL;

    int pkg_len = m_p2p->get_p2p_protocol_impl().BuildPkg(host, pkg);

    if (pkg_len < 0)
    {
        return false;
    }

    if (!m_session)
    {
        return false;
    }

    return m_p2p->get_net_manager()->Send(m_session, pkg, pkg_len);
}

void CP2PSession::DisConnect( void )
{
    if (m_session)
    {
        m_p2p->get_net_manager()->DisConnect(m_session);
        m_session = NULL;
    }
}

void CP2PSession::Reset( void )
{
    m_p2p = NULL;
    m_p2p_id = 0;
    m_local_ip = 0;
    m_local_port = 0;
    m_peer_ip = 0;
    m_peer_port = 0;
    m_net_handle = NULL;
    m_session = NULL;
    m_stat = P2P_STAT_INT;
}

CNATTestSession::CNATTestSession( void )
{
}

void CNATTestSession::OnEstablish( HNETHANDLE hHandle, HSESSION hSession )
{
    NATTestReq test;
    
    test.local_ip = m_p2p->get_net_manager()->GetLocalIP(hSession);
    test.local_port = m_p2p->get_net_manager()->GetLocalPort(hSession);
    test.p2p_id = m_p2p->get_p2p_id();

    SendPkg(&test);
}

void CNATTestSession::OnTerminate( HSESSION hSession )
{
    m_p2p->get_p2p_session_manager().get_nat_test_session_pool().FreeObj(this);
}

void CNATTestSession::OnError( HNETHANDLE hHandle, HSESSION hSession, INT32 iModuleError, INT32 iSystemError )
{
    if (iModuleError == NET_CONNECT_FAIL)
    {
        m_p2p->get_p2p_session_manager().get_nat_test_session_pool().FreeObj(this);
    }
}

bool CNATTestSession::SendPkg( void* host )
{
    char* pkg = NULL;

    int pkg_len = m_p2p->get_p2p_protocol_impl().BuildPkg(host, pkg);

    if (pkg_len < 0)
    {
        return false;
    }

    if (!m_session)
    {
        return false;
    }

    return m_p2p->get_net_manager()->Send(m_session, pkg, pkg_len);
}

bool CNATTestSession::Test( UINT32 local_ip, UINT16 local_port, UINT32 peer_ip, UINT16 peer_port )
{
    char local_ip_str[32];
    char nat_test_ip[32];

    sockaddr_in addr;
    addr.sin_addr.s_addr = local_ip;
    strcpy(local_ip_str, inet_ntoa(addr.sin_addr));

    addr.sin_addr.s_addr = peer_ip;
    strcpy(nat_test_ip, inet_ntoa(addr.sin_addr));

    m_session = m_p2p->get_net_manager()->Connect(nat_test_ip, ntohs(peer_port), 1024, 1024, &m_p2p->get_pkg_parser(), local_ip_str, ntohs(local_port), true);
    if (m_session)
    {
        m_p2p->get_net_manager()->SetSessionUserData(m_session, this);
        return true;
    }

    return false;
}



void CPunchSession::OnEstablish( HNETHANDLE hHandle, HSESSION hSession )
{
    m_p2p->get_net_manager()->DisConnect(hSession);
}

void CPunchSession::OnTerminate( HSESSION hSession )
{
    m_p2p->get_p2p_timer_manager().DelTimer(this);
    m_p2p->get_p2p_session_manager().get_punch_session_pool().FreeObj(this);
}

void CPunchSession::OnError( HNETHANDLE hHandle, HSESSION hSession, INT32 iModuleError, INT32 iSystemError )
{
    if (iModuleError == NET_CONNECT_FAIL)
    {
        m_session = NULL;
        if (get_on_time_count() == get_count())
        {
            m_p2p->get_p2p_session_manager().get_punch_session_pool().FreeObj(this);
        }
    }
}

void CPunchSession::OnRecv( HSESSION hSession, const char* pData, const INT32 iLen )
{

}

bool CPunchSession::Punch( UINT32 peer_ip, UINT16 peer_port, INT32 count, INT32 elapse )
{
    set_peer_ip(peer_ip);
    set_peer_port(peer_port);

    set_local_ip(m_p2p->get_net_manager()->GetLocalIP(m_p2p->get_host().get_session()));
    set_local_port(m_p2p->get_net_manager()->GetLocalPort(m_p2p->get_host().get_session()));

    if (!Connect())
    {
        return false;
    }

    set_elapse(count);

    set_count(elapse);

    set_on_time_count(0);

    return m_p2p->get_p2p_timer_manager().AddTimer(this);
}

void CPunchSession::OnTimer( void )
{
    m_on_time_count++;
    if (m_session)
    {
        return;
    }

    Connect();
}

bool CPunchSession::Connect( void )
{
    char local_ip[32];
    char peer_ip[32];

    sockaddr_in addr;
    addr.sin_addr.s_addr = m_local_ip;
    strcpy(local_ip, inet_ntoa(addr.sin_addr));

    addr.sin_addr.s_addr = m_peer_ip;
    strcpy(peer_ip, inet_ntoa(addr.sin_addr));

    m_session = m_p2p->get_net_manager()->Connect(peer_ip, ntohs(m_peer_port), 1024, 1024, &(m_p2p->get_pkg_parser()), local_ip, ntohs(m_local_port), true);
    if (m_session)
    {
        m_p2p->get_net_manager()->SetSessionUserData(m_session, this);

        return true;
    }

    return false;
}
